package com.ctg.behavior.calc.impala.builder.userpath;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.ctg.behavior.calc.common.CtPathNode;
import com.ctg.behavior.calc.impala.utils.CtCalcRowsUtils;
import com.ctg.behavior.calc.utils.CtCalcUtils;
import com.ctg.behavior.common.userpath.CtUserPathCalcData;
import com.ctg.behavior.common.userpath.CtUserPathLink;
import com.ctg.behavior.common.userpath.CtUserPathNode;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class CtUserPathResultBuilder {

	// KEY:
	// ColumnIndex+"-"+eventId+"-"+property+"-"+{byValue}+"@"+{event顺序号}
	private static ThreadLocal<Map<String, List<String>>> indexPathNodeKeys = new ThreadLocal<>();
	private static ThreadLocal<Map<String, CtPathNode>> indexPathNodes = new ThreadLocal<>();
	// KEY:
	// ColumnIndex+"-"+eventId+"-"+property+"-"+{byValue}
	private static ThreadLocal<Map<String, CtUserPathNode>> indexCalcDataNodes = new ThreadLocal<>();

	public void resetResultBuilderThreadLocal() {
		{
			Map<String, List<String>> localV = new LinkedHashMap<>();
			indexPathNodeKeys.set(localV);
		}
		{
			Map<String, CtPathNode> localV = new LinkedHashMap<>();
			indexPathNodes.set(localV);
		}
		{
			Map<String, CtUserPathNode> localV = new LinkedHashMap<>();
			indexCalcDataNodes.set(localV);
		}
	}

	public CtUserPathCalcData doBuilder(CtUserPathCalcData calcData) {

		List<String> pathNodeKeys = new ArrayList<>(indexPathNodes.get().keySet());
		for (String pathNodeKey : pathNodeKeys) {
			int columnIndex = CtCalcUtils.getPathNodeColumnIndex(pathNodeKey);
			if (columnIndex < 0) {
				log.error("pathNodeKey={}", pathNodeKey);
				continue;
			}
			/////////////////////////////////////////////////////////
			////// 1.填充响应报文中：节点信息
			{
				// 1.1 初化UserPathNode数组
				List<List<CtUserPathNode>> nodes = calcData.getNodes();
				for (int index = nodes.size(); index <= columnIndex; index++) {
					nodes.add(new ArrayList<CtUserPathNode>());
				}
				List<List<CtUserPathLink>> links = calcData.getLinks();
				for (int index = links.size(); index <= columnIndex; index++) {
					links.add(new ArrayList<CtUserPathLink>());
				}
			}
			// 2.1 填充响应报文中：节点信息
			String calcDataNodeKey = CtCalcRowsUtils.fetchResultUserPathNodeKey(pathNodeKey);
			{
				CtPathNode pathNode = indexPathNodes.get().get(pathNodeKey);

				CtUserPathNode calcDataNode = indexCalcDataNodes.get().get(calcDataNodeKey);
				if (null == calcDataNode) {
					calcDataNode = new CtUserPathNode();
					indexCalcDataNodes.get().put(calcDataNodeKey, calcDataNode);

					calcDataNode.setEventId(pathNode.getEventId());
					calcDataNode.setId(calcDataNodeKey);
					calcDataNode.setByValues(pathNode.getByValue());

					calcData.getNodes().get(columnIndex).add(calcDataNode);
				}
				calcDataNode.setTimes(calcDataNode.getTimes() + pathNode.getTotal());
			}
			List<String> subPathNodeKeys = indexPathNodeKeys.get().get(pathNodeKey);
			if (null == subPathNodeKeys) {
				// 此节点已有无子节点
				continue;
			}
			/////////////////////////////////////////////////////////
			////// 2.填充响应报文中：连线信息
			// 2.1 处理Node Link中首节点wastage(流失)
			{
				CtPathNode topNodeOfLink = indexPathNodes.get().get(pathNodeKey);
				CtUserPathLink userpathLink = new CtUserPathLink();
				userpathLink.setSource(calcDataNodeKey);
				userpathLink.setTarget(topNodeOfLink.getSeqNo() + "-wastage");
				userpathLink.setIsWastage(true);
				Integer times = topNodeOfLink.getTotal() - topNodeOfLink.getRetention();
				times = times < 0 ? 0 : times;
				userpathLink.setTimes(times);
				calcData.getLinks().get(columnIndex).add(userpathLink);
			}
			// 2.2 处理Node Link中
			for (int index = 0; index < subPathNodeKeys.size(); index++) {
				String subPathNodeKey = subPathNodeKeys.get(index);
				CtPathNode subPathNode = indexPathNodes.get().get(subPathNodeKey);
				if (null == subPathNode) {
					// 异常数据
					log.error("subPathNode is null, subPathNodeKey={}", subPathNodeKey);
					continue;
				}
				CtUserPathLink userpathLink = new CtUserPathLink();
				userpathLink.setIsWastage(false);
				userpathLink.setSource(calcDataNodeKey);
				userpathLink.setTarget(CtCalcRowsUtils.fetchResultUserPathNodeKey(subPathNodeKey));
				userpathLink.setTimes(subPathNode.getTotal());
				calcData.getLinks().get(columnIndex).add(userpathLink);
			}
		}

		return calcData;
	}

	public void doNodeBuilder(CtPathNode upperPathNode, final List<CtPathNode> columnNodes, List<String> byFields) {

		log.info("columnNodes={}", JSON.toJSONString(columnNodes));
		if (columnNodes.isEmpty()) {
			return;
		}

		// 本次事件所在节点的上级节点
		String upperPathNodeKey = CtCalcRowsUtils.buildPathNodeKey(upperPathNode);

		// Step1. 把每次的计算结算缓存到ThreadLocal中
		for (CtPathNode oneNode : columnNodes) {
			// 1. 取出事件标识及对应的计算数值
			Integer total = oneNode.getTotal();

			// 2. 组建本次事件的NodeKey，缓存计算结果
			String nodeKey = CtCalcRowsUtils.buildPathNodeKey(oneNode);
			indexPathNodes.get().put(nodeKey, oneNode);

			// 3. 若上级Node不存在，即：本次Node为最上层Node,则不用累计，也不用添加缓存到inexNodeKeys
			if (!StringUtils.isEmpty(upperPathNodeKey)) {
				// 3.1. 把计算累计加上级节点Node
				CtPathNode upperLocalNode = indexPathNodes.get().get(upperPathNodeKey);
				if (null != upperLocalNode) {
					upperLocalNode.setRetention(upperLocalNode.getRetention() + total);
				}
				// 3.2 记录Node上下级节点关系
				List<String> nodeKeys = indexPathNodeKeys.get().get(upperPathNodeKey);
				if (null == nodeKeys) {
					nodeKeys = new ArrayList<>();
					indexPathNodeKeys.get().put(upperPathNodeKey, nodeKeys);
				}
				nodeKeys.add(nodeKey);
			}

		}

		log.info("inexNodeKeys={}", JSON.toJSONString(indexPathNodeKeys));
		log.info("indexNodes={}", JSON.toJSONString(indexPathNodes));

	}

}
